package qj.app.trader;

import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import qj.app.trader.ParseRule.RuleMatch;
import qj.util.RegexUtil;
import qj.util.funct.P1;

public class Reader {

	private ParseRule rule;

	public Reader(ParseRule rule) {
		this.rule = rule;
	}

	// Try read word
	// If normal word -> apply rules
	// If normal word but no rule, try extend more normal words
	// If not normal word but complex, try separate and apply rules with each part
	// If not normal word but marks, apply special rules
	// If success reading, move index and continue until end of document
	public FirstStepReading read(String content) {
		FirstStepReading result = new FirstStepReading();
		
		ReaderIndex index = new ReaderIndex(content);
		
		while (true) {
			if (index.expandWord()) {
//				System.out.println(index.expandContent());
				if (index.isNormalWord()) {
					// Apply rule or expand more word
					RuleMatch match = rule.apply(index.expandContent(), this);
					if (match != null) {
						applyMatch(match, result, index);
						index.fix();
					} else {
						// Try expand
						match = tryExpand(index, result);
						if (match != null) {
							applyMatch(match, result, index);
							index.fix();
						} else {
							// if expand fail -> not mark area
							index.reset();
							index.expandWord();
							index.fix();
						}
						
					}
					
					continue;
				} else if (index.isComplexWord()) {
					tryComplexWord(index, result);
					index.fix();
				} else if (index.isMark()) {
					applyMark(index.expandContent());
					//this.reset();
				}
			} else {
				if (index.isEnd()) {
					return result;
				}
			}
			index.fix();
		}
	}

	private void tryComplexWord(ReaderIndex index, FirstStepReading result) {
		String content = index.expandContent();
		// Detach parts and try
		List<String> detachedComplex = detachComplex(content);
		for (String detached : detachedComplex) {
			RuleMatch match = rule.apply(detached, this);
			if (match!=null) {
				applyMatch(match, result, index);
			}
		}
	}

	private List<String> detachComplex(final String content) {
		final LinkedList<String> ret = new LinkedList<String>();
		final int[] index = {0};
		RegexUtil.each(RegexUtil.compileF.e("[\\d.,]+"), content, new P1<Matcher>() {public void e(Matcher m) {
			if (m.start() > index[0]) {
				ret.add(content.substring(m.start() - index[0]));
			}
			
			ret.add(m.group());
			
			index[0] = m.end();
		}});
		if (index[0] < content.length()) {
			ret.add(content.substring(index[0]));
		}
		return ret;
	}

	private void applyMatch(RuleMatch match, FirstStepReading result, ReaderIndex index) {
		// TODO Auto-generated method stub
		// mark as processed area
		result.addMatch(match, index);
	}
	
	public static class ReadState {
		
	}

	private RuleMatch tryExpand(ReaderIndex index, FirstStepReading result) {
		while (true) {
			if (index.expandNormalWord()) {
				RuleMatch match = rule.apply(index.expandContent(), this);
				if (match!= null) {
					return match;
				} else {
					continue;
				}
			} else {
				return null;
			}
		}
	}

	private void applyMark(String mark) {
		// TODO Auto-generated method stub
		if (",".equals(mark)) {
			return;
		} else if (mark.contains(".") || mark.contains(";")) {
			reset();
			return;
		}
		System.out.println("Unknown mark [" + mark + "]");
	}

	private void reset() {
		// TODO Auto-generated method stub
		
	}


}
